#pragma once
#include <brpc/channel.h>
#include <string>
#include <vector>
#include <unordered_map>
#include <mutex>
#include "logger.hpp"

namespace suye 
{
// 封装单个服务的信道管理类
class ServiceChannel 
{
public:
    using ptr = std::shared_ptr<ServiceChannel>;
    using ChannelPtr = std::shared_ptr<brpc::Channel>;
   
    ServiceChannel(const std::string& service_name)
        : _service_name(service_name)
        , _index(0)
    {}

    // 服务新上线了一个节点，则调用Append方法新增信道
    void Append(const std::string& host)
    {
        auto channel = std::make_shared<brpc::Channel>();
        brpc::ChannelOptions options;
        options.connect_timeout_ms = -1;    
        options.timeout_ms = -1;           
        options.max_retry = 3;              
        options.protocol = "baidu_std";     
        int ret = channel->Init(host.c_str(), &options);
        if(ret == -1)
        {
            LOG_ERROR("初始化{}-{}信道失败！", _service_name, host);
            return;
        }
        std::unique_lock<std::mutex> lock(_mutex);
        _hosts.insert({host, channel});
        _channels.push_back(channel);
    }

    // 服务下线了一个节点，则调用Remove方法删除信道
    void Remove(const std::string& host)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _hosts.find(host);
        if(it == _hosts.end())
        {
            LOG_WARN("删除{}-{}信道失败，不存在！", _service_name, host);
            return;
        }
        for(auto vit = _channels.begin(); vit != _channels.end(); ++vit)
        {
            if(*vit == it->second) 
            {
                _channels.erase(vit);
                break;
            }
        }
        _hosts.erase(it);
    }

    // 通过RR轮转策略，获取一个Channel用于发起对应服务的RPC调用
    ChannelPtr Choose()
    {
        std::unique_lock<std::mutex> lock(_mutex);
        if(_channels.empty()) 
        {
            LOG_WARN("{}服务不存在可用的节点！", _service_name);
            return nullptr;
        }
        int32_t idx = _index++ % _channels.size();
        return _channels[idx];
    }

private:
    std::mutex _mutex;                  // 互斥锁
    int32_t _index;                     // 当前轮转下标计数器
    std::string _service_name;          // 服务名称
    std::vector<ChannelPtr> _channels;  // 当前服务对应的信道集合
    std::unordered_map<std::string, ChannelPtr> _hosts;  // 主机地址到信道的映射
};

// 总体的服务信道管理类
class ServiceManager
{
public:
    using ptr = std::shared_ptr<ServiceManager>;
    
    // 获取指定服务的节点信道
    ServiceChannel::ChannelPtr Choose(const std::string& service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _services.find(service_name);
        if(it == _services.end())
        {
            LOG_WARN("{}服务不存在可用的节点！", service_name);
            return nullptr;
        }
        return it->second->Choose();
    }

    // 声明关注哪些服务的上下线，不关心的就不需要管理
    void Declared(const std::string& service_name)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _follow_services.insert(service_name);
    }

    // 服务上线时调用的回调接口，将服务节点管理起来
    void OnServiceOnline(const std::string& service_instance, const std::string& host)
    {
        std::string service_name = GetServiceName(service_instance);
        ServiceChannel::ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto fit = _follow_services.find(service_name);
            if(fit == _follow_services.end())
            {
                LOG_DEBUG("{}-{}服务上线了，但是不关注，无需管理！", service_name, host);
                return;
            }
            // 先获取管理对象，没有则创建，有则添加节点
            auto it = _services.find(service_name);
            if(it == _services.end())
            {
                service = std::make_shared<ServiceChannel>(service_name);
                _services.insert({service_name, service});
            }
            else
            {
                service = it->second;
            }
        }
        if(!service)
        {
            LOG_ERROR("创建{}服务管理节点失败！", service_name);
        }
        service->Append(host);
        LOG_DEBUG("{}-{}服务节点上线成功，进行添加管理！", service_name, host);
    }

    // 服务下线时调用的回调接口，从服务信道管理中，删除指定节点信道
    void OnServiceOffline(const std::string& service_instance, const std::string& host)
    {
        std::string service_name = GetServiceName(service_instance);
        ServiceChannel::ptr service;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto fit = _follow_services.find(service_name);
            if(fit == _follow_services.end())
            {
                LOG_DEBUG("{}-{}服务下线了，但是不关注，无需管理！", service_name, host);
                return;
            }
            // 先获取管理对象，没有则创建，有则添加节点
            auto it = _services.find(service_name);
            if(it == _services.end())
            {
                LOG_WARN("删除{}服务节点时，没有找到管理对象！", service_name);
                return;
            }
            service = it->second;
        }
        service->Remove(host);
        LOG_DEBUG("{}服务节点{}下线成功！", service_name, host);
    }
private:
    std::string GetServiceName(const std::string& service_instance)
    {
        auto pos = service_instance.find_last_of('/');
        if(pos == std::string::npos)
        {
            return service_instance;
        }
        return service_instance.substr(0, pos);
    }

private:
    std::mutex _mutex;
    std::unordered_set<std::string> _follow_services;                // 关注的服务名称集合
    std::unordered_map<std::string, ServiceChannel::ptr> _services;  // 服务名称到服务信道的映射
};
}


